package com.huahai.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huahai.constant.UserConstant;
import com.huahai.exception.BusinessException;
import com.huahai.exception.ErrorCode;
import com.huahai.manager.auth.StpKit;
import com.huahai.mapper.UserMapper;
import com.huahai.pojo.dto.user.UserLoginDTO;
import com.huahai.pojo.dto.user.UserQueryDTO;
import com.huahai.pojo.dto.user.UserRegisterDTO;
import com.huahai.pojo.dto.user.UserUpdateDTO;
import com.huahai.pojo.entity.User;
import com.huahai.pojo.enums.UserRoleEnums;
import com.huahai.pojo.vo.user.UserLoginVO;
import com.huahai.pojo.vo.user.UserVO;
import com.huahai.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author huahai
 * @description 针对表【user(用户)】的数据库操作Service实现
 * @createDate 2025-07-17 09:42:55
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    // 默认用户名前缀
    private static final String USER_NAME_PREFIX = "用户";
    // 默认头像
    private static final String DEFAULT_AVATAR = "https://javawebprogram.oss-cn-beijing.aliyuncs.com/2025/07/96e4337a-ca4d-49bf-be07-43bd3af88f90.webp";
    // 默认简介
    private static final String DEFAULT_PROFILE = "这个人很懒，什么都没有留下";

    /**
     * 用户注册
     *
     * @param userRegisterDTO
     * @return
     */
    @Override
    public Long userRegister(UserRegisterDTO userRegisterDTO) {
        // 1. 校验参数
        String userAccount = userRegisterDTO.getUserAccount();
        String userPassword = userRegisterDTO.getUserPassword();
        String checkPassword = userRegisterDTO.getCheckPassword();
        if (StrUtil.hasBlank(userAccount, userPassword, checkPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号过短");
        }
        if (userPassword.length() < 8 || checkPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码过短");
        }
        if (!userPassword.equals(checkPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次输入的密码不一致");
        }
        // 2. 判断用户名在数据库中是否存在
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("userAccount", userAccount);
        long count = this.count(userQueryWrapper);
        if (count > 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号已存在");
        }
        // 3. 对密码进行md5单向加密
        String encryptionPassword = getEncryptionPassword(userPassword);
        // 4. 存储用户基本信息并返回结果
        String defaultUserName = USER_NAME_PREFIX + IdUtil.simpleUUID().substring(0, 10);
        User user = new User();
        user.setUserAccount(userAccount);
        user.setUserPassword(encryptionPassword);
        user.setUserName(defaultUserName);
        user.setUserAvatar(DEFAULT_AVATAR);
        user.setUserProfile(DEFAULT_PROFILE);
        user.setUserRole(UserRoleEnums.USER.getValue());

        this.save(user);
        // 主键回显
        return user.getId();
    }

    /**
     * 用户登录
     *
     * @param userLoginDTO 用户登录信息
     * @param request      请求
     * @return 用户信息
     */
    @Override
    public UserLoginVO userLogin(UserLoginDTO userLoginDTO, HttpServletRequest request) {
        // 1. 校验参数
        String userAccount = userLoginDTO.getUserAccount();
        String userPassword = userLoginDTO.getUserPassword();
        if (StrUtil.hasBlank(userAccount, userPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号错误");
        }
        if (userPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码错误");
        }
        // 2. 加密密码
        String encryptionPassword = getEncryptionPassword(userPassword);
        // 3. 查询数据库是否存在和一致
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("userAccount", userAccount);
        userQueryWrapper.eq("userPassword", encryptionPassword);
        User user = this.getOne(userQueryWrapper);
        if (user == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在或密码错误");
        }
        // 4. 存储user信息到session中
        request.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, user);
        // 5. 记录用户登录态到 Sa-token，便于空间鉴权时使用，注意保证该用户信息与 SpringSession 中的信息过期时间一致
        StpKit.SPACE.login(user.getId());
        StpKit.SPACE.getSession().set(UserConstant.USER_LOGIN_STATE, user);
        // 6.封装UserLoginVO并返回
        return getUserLoginVO(user);
    }

    /**
     * 获取当前登录用户
     *
     * @param request 请求
     * @return 当前登录用户
     */
    @Override
    public User getLoginUser(HttpServletRequest request) {
        // 1. 获取当前session中存放的用户
        Object userObject = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        User loginUser = (User) userObject;
        // 2. 判空
        if (loginUser == null || loginUser.getId() == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        // 3. 对数据库进行查询（不追求极致性能的话，防止用户信息被修改导致不同步）
        Long userId = loginUser.getId();
        loginUser = this.getById(userId);
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        // 4. 返回user信息
        return loginUser;
    }

    /**
     * 用户退出登录
     *
     * @param request 请求
     * @return 退出登录结果
     */
    @Override
    public Boolean userLogout(HttpServletRequest request) {
        // 1. 判断当前是否登陆
        Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        if (userObj == null) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "未登录");
        }
        // 2. 移除登录态(session)
        request.getSession().removeAttribute(UserConstant.USER_LOGIN_STATE);
        return true;
    }

    /**
     * 获取md5加密后的密码
     *
     * @param password 原始密码
     * @return 加密后的密码
     */
    @Override
    public String getEncryptionPassword(String password) {
        // 1. 校验参数
        if (StrUtil.isBlank(password)) {
            return null;
        }
        // 2. 加盐，混淆参数
        String salt = "huahai";
        return DigestUtils.md5DigestAsHex((salt + password).getBytes());
    }

    /**
     * 获取脱敏后端用户信息
     *
     * @param user 用户信息
     * @return 脱敏后的用户信息
     */
    @Override
    public UserLoginVO getUserLoginVO(User user) {
        if (user == null) {
            return null;
        }
        UserLoginVO userLoginVO = new UserLoginVO();
        BeanUtils.copyProperties(user, userLoginVO);
        return userLoginVO;
    }

    /**
     * 获取脱敏后用户信息 （展示给用户查询其他用户）
     *
     * @param user 用户信息
     * @return 脱敏后的用户信息
     */
    @Override
    public UserVO getUserVO(User user) {
        if (user == null) {
            return null;
        }
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user, userVO);
        return userVO;
    }

    /**
     * 获取脱敏后的用户信息列表
     *
     * @param userList 用户信息列表
     * @return 脱敏后的用户信息列表
     */
    @Override
    public List<UserVO> getUserVOList(List<User> userList) {
        // 判断
        if (CollectionUtils.isEmpty(userList)) {
            return Collections.emptyList();
        }
        // 封装userVO列表返回
        return userList.stream().map(this::getUserVO).collect(Collectors.toList());
    }

    /**
     * 封装查询用户的查询条件
     *
     * @param userQueryDTO 查询条件
     * @return
     */
    @Override
    public QueryWrapper<User> getQueryWrapper(UserQueryDTO userQueryDTO) {
        // 判空
        if (userQueryDTO == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数为空");
        }
        // 组合查询条件
        Long id = userQueryDTO.getId();
        String userAccount = userQueryDTO.getUserAccount();
        String userName = userQueryDTO.getUserName();
        String userProfile = userQueryDTO.getUserProfile();
        String userRole = userQueryDTO.getUserRole();
        Long vipNumber = userQueryDTO.getVipNumber();
        String sortField = userQueryDTO.getSortField();
        String sortOrder = userQueryDTO.getSortOrder();
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(ObjUtil.isNotNull(id), "id", id);
        queryWrapper.eq(StrUtil.isNotBlank(userRole), "userRole", userRole);
        queryWrapper.like(StrUtil.isNotBlank(userAccount), "userAccount", userAccount);
        queryWrapper.like(StrUtil.isNotBlank(userName), "userName", userName);
        queryWrapper.like(StrUtil.isNotBlank(userProfile), "userProfile", userProfile);
        queryWrapper.eq(ObjUtil.isNotNull(vipNumber), "vipNumber", vipNumber);
        queryWrapper.orderBy(StrUtil.isNotEmpty(sortField), "ascend".equals(sortOrder), sortField);
        // 返回
        return queryWrapper;
    }

    /**
     * 封装更新user的参数
     *
     * @param userUpdateDTO 修改用户参数
     * @return user参数
     */
    @Override
    public UpdateWrapper<User> getUserUpdateWrapper(UserUpdateDTO userUpdateDTO, User loginUser) {
        // 封装更新user参数
        UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
        userUpdateWrapper.eq("id", userUpdateDTO.getId());
        if (userUpdateDTO.getUserName() != null) {
            userUpdateWrapper.set("userName", userUpdateDTO.getUserName());
        }
        if (userUpdateDTO.getUserAvatar() != null) {
            userUpdateWrapper.set("userAvatar", userUpdateDTO.getUserAvatar());
        }
        if (userUpdateDTO.getUserProfile() != null) {
            userUpdateWrapper.set("userProfile", userUpdateDTO.getUserProfile());
        }
        // 判断是否为管理员,不是不允许普通用户修改
        if (userUpdateDTO.getUserRole() != null && !userUpdateDTO.getUserRole().equals(UserConstant.ADMIN_ROLE)) {
            userUpdateWrapper.set("userRole", userUpdateDTO.getUserRole());
        }
        // 用户修改密码的模块
        String userPassword = userUpdateDTO.getUserPassword();
        String newPassword = userUpdateDTO.getNewPassword();
        String checkPassword = userUpdateDTO.getCheckPassword();
        // 定义是否为修改密码的场景
        boolean isUpdatePassword = !(StrUtil.isBlank(userPassword) && StrUtil.isBlank(newPassword) && StrUtil.isBlank(checkPassword));
        if(isUpdatePassword){
            if (StrUtil.hasBlank(userPassword, newPassword, checkPassword)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码不能为空");
            } else {
                // 判断密码长度
                if (userPassword.length() < 8 || newPassword.length() < 8 || checkPassword.length() < 8) {
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码长度不能小于8位");
                }
                // 判断两次输入的密码是否一致
                if (!newPassword.equals(checkPassword)) {
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次输入的密码不一致");
                }
                // 对老密码进行我们规定的加密
                String md5OldPassword = getEncryptionPassword(userPassword);
                User user = this.getById(loginUser.getId());
                // 判断加密后的老密码是否与老密码一致
                if (!user.getUserPassword().equals(md5OldPassword)) {
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "旧密码输入有误");
                }
                // 对新密码进行我们规定的加密
                String md5NewPassword = getEncryptionPassword(newPassword);
                // 存入修改条件
                userUpdateWrapper.set("userPassword", md5NewPassword);
            }
        }

        return userUpdateWrapper;
    }

    /**
     * 判断是否为管理员
     *
     * @param user 用户信息
     * @return 是否为管理员
     */
    @Override
    public boolean isAdmin(User user) {
        return user != null && UserRoleEnums.ADMIN.getValue().equals(user.getUserRole());
    }


}




